package com.design.pattern.singleton;

public class Singleton3 {
//双重锁，线程安全
    private  volatile static Singleton3 singleton;

    private Singleton3(){
            System.out.println("当前线程:"+Thread.currentThread().getName());
    }

    public static Singleton3 getInstance(){
        if(singleton == null){
            synchronized (Singleton3.class){
                if(singleton == null){
                    singleton = new Singleton3();
                    //当执行 singleton = new Singleton3();时，需要进行以下三步非原子操作
                    //1.分配对象内存
                    //2.调用构造器方法，执行初始化
                    //3.将对象引用赋值给变量。
                    //2-3可能发生重排->此处重排后会发有什么影响???
                    /*  https://blog.csdn.net/weixin_37817685/article/details/80261549
                    由于有一个『singleton已经不为null但是仍没有完成初始化』的中间状态，而这个时候，
                    如果有其他线程刚好运行到第一层if (instance ==null)这里，
                    这里读取到的instance已经不为null了，所以就直接把这个中间状态的instance拿去用了，
                    就会产生问题。这里的关键在于线程T1对ingleton的写操作没有完成，线程T2就执行了读操作。
                     */



                    //synchronized 无法保证指令重排，但volatile可以
                    //若不加volatile则会发生指令重排，防止其他线程访问到一个未初始化的对象
                }
            }
        }

        return singleton;

    }

    public static void main(String[] args){

        for(int i=0;i<1000;i++){
            new Thread(()->{
                Singleton3.getInstance();
            }).start();
        }

    }

}
